<?php
/**
 * Classe qui gère les planètes d'un joueur
 *
 * @version 1.0
 * @author jonathan <jo.link.noir@gmail.com>
 * @date 27-05-2010
 *
 * @exceptions
 * SW_Planet_Exception :
 * 	1 => Planète inexistante
 */
class SW_Planet implements Iterator, Countable
{
	/** @var string */
	const INDEX = 'planet';


	/** @var SW_Player */
	protected $player;

	/** @var array : {idplanets => SW_Planet_Element, ...} */
	protected $planets = array();

	/** @var int : id de la planete actuelle */
	protected $currentId = null;

	/** @var array : {idplanets => {instance => SW_Planet_Storage_Treatment, ...}, ...}*/
	protected $storageElements = array();


	/**
	 * Ajoute la planète au joueur. Peut être récupère ainsi
	 * @param SW_Player $player
	 */
	public function __construct(SW_Player $player)
	{
		$player[self::INDEX] = $this;
		$this->player = $player;
	}

	public function __destruct()
	{
		foreach ($this->storageElements as $storages)
			foreach ($storages as $storage)
				$storage->__destruct();
	}

	/**
	 * Ajoute une planète
	 * @param SW_Planet_Element $planet
	 */
	public function add(SW_Planet_Element $planet)
	{
		$this->planets[$planet->getId()] = $planet;
		if (!isset($this->storageElements[$planet->getId()]))
			$this->storageElements[$planet->getId()] = array();
	}

	/**
	 * Ajoute un élément dans une planète
	 * @param SW_Planet_Storage_Treatment $element
	 * @param string $instance
	 * @param int $idPlanet
	 */
	public function addStorageElement(SW_Planet_Storage_Treatment $element, $instance, $idPlanet)
	{
		$this->storageElements[$idPlanet][$instance] = $element;
	}

	/**
	 * Retourne la planète actuelle
	 * @return SW_Planet_Element
	 */
	public function getCurrentPlanet()
	{
		return $this->planets[$this->currentId];
	}

	/**
	 * Définie la planète actuelle
	 * @param int $id = null : si null alors la première planète sera sélectionée
	 * @exception SW_Planet_Exception Planète inexistante
	 */
	public function setCurrentId($id = null)
	{
		if (null === $id)
		{
			foreach ($this->planets as $id => $p)
			{
				$this->currentId = $id;
				return;
			}
		}
		$id = (int)$id;
		if (isset($this->planets[$id]))
			$this->currentId = $id;
		else
			throw new SW_Planet_Exception('Planète inexistante', 1);
	}

	/**
	 * @return int : id de la planète actuelle
	 */
	public function getCurrentId()
	{
		return $this->currentId;
	}

	/**
	 * @param int $id
	 * @return SW_Planet_Element
	 */
	public function get($id)
	{
		return $this->planets[$id];
	}

	/**
	 * Retourne toutes les planètes
	 * @return array : {id => SW_Planet_Element, ...}
	 */
	public function gets()
	{
		return $this->planets;
	}

	/**
	 * Retourne un tableaux d'id des planètes
	 * @return array : {int, ...}
	 */
	public function getIds()
	{
		return array_keys($this->planets);
	}

	/**
	 * Vérifie l'id de la planète existe
	 * @param int $id
	 * @return bool
	 */
	public function exists($id)
	{
		return isset($this->planets[$id]);
	}

	/**
	 * Retourne un objet enfant de la planète actuelle
	 * @param string $instance
	 * @code
		return $this->getInstance($instance, $this->currentId);
	 * @endcode
	 * @return SW_Planet_Storage_Treatment|null
	 */
	final public function getCurrentInstance($instance)
	{
		return $this->getInstance($instance, $this->currentId);
	}

	/**
	 * Retourne l'instance si elle existe
	 * @param string $instance
	 * @param int $idPlanet
	 * @return SW_Planet_Storage_Treatment|null
	 */
	final public function getInstanceIfExists($instance, $idPlanet)
	{
		return isset($this->storageElements[$idPlanet], $this->storageElements[$idPlanet][$instance])
			? $this->getInstance($instance, $idPlanet)
			: null;
	}

	/**
	 * Retourne les instances existantes
	 * @param int $idPlanet
	 * @param bool $nullIfEmpty = false : si true alors null est retourner si aucun noms
	 * @return null|array(string, …)
	 */
	final public function getInstancesNames($idPlanet, $nullIfEmpty = false)
	{
		return isset($this->storageElements[$idPlanet])
			? array_keys($this->storageElements[$idPlanet])
			: ($nullIfEmpty ? null : array());
	}

	/**
	 * Retourne un objet enfant de la planète demandée
	 * @param string $instance
	 * @param int $idPlanet
	 * @return SW_Planet_Storage_Treatment|null
	 */
	public function getInstance($instance, $idPlanet)
	{
		return isset($this->storageElements[$idPlanet])
			? (
				isset($this->storageElements[$idPlanet][$instance])
					? $this->storageElements[$idPlanet][$instance]
					: $this->initInstance($instance, $idPlanet)
			) : null;
	}

	/**
	 * Retourne un objet enfant de la planete itérée
	 * @param string $instance
	 * @code
		return $this->getInstance($instance, key($this->planets));
	 * @endcode
	 * @return SW_Planet_Storage_Treatment|null
	 */
	final public function getInstanceIterator($instance)
	{
		return $this->getInstance($instance, key($this->planets));
	}

	/**
	 * Initialise l'instance et la retourne si celle-ci n'exista pas.
	 * @param string $instance
	 * @param int $idPlanet
	 * @return SW_Planet_Storage_Treatment|null
	 */
	protected function initInstance($instance, $idPlanet)
	{
		return null;
	}

	/**
	 * Vérifie l'instance de la planète
	 * @param string $instance
	 * @param int $idPlanet
	 * @return bool
	 */
	final public function existsInstance($instance, $idPlanet)
	{
		return isset($this->planets[$idPlanet], $this->storageElements[$idPlanet][$instance]);
	}

	/**
	 * @return SW_Player
	 */
	public function getPlayer()
	{
		return $this->player;
	}

	/**
	 * @return int
	 */
	public function count()
	{
		return count($this->planets);
	}

	/**
	 * @return bool
	 */
	public function valid()
	{
		return NULL !== key($this->planets);
	}

	/**
	 * @code
		next($this->planets);
	 * @endcode
	 */
	public function next()
	{
		next($this->planets);
	}

	/**
	 * @code
		reset($this->planets)
	 * @endcode
	 */
	public function rewind()
	{
		reset($this->planets);
	}

	/**
	 * @code
		key($this->planets)
	 * @endcode
	 * @return int
	 */
	public function key()
	{
		return key($this->planets);
	}

	/**
	 * @return SW_Planet_Element
	 */
	public function current()
	{
		return current($this->planets);
	}
}